package cn.kjcoder.redis.controller;

import com.sun.org.apache.bcel.internal.generic.NEW;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author hkj
 * @email 1349091387@qq.com
 * @date 2022/1/20
 * 源码允许修改，并且本人十分乐意有 大佬 来对代码进行 随 意 调 教
 **/
@RestController
@Slf4j
@RequestMapping("/redPacket")
public class RedPacketController {

    @Autowired
    private RedisTemplate redisTemplate;

    public static final String RED_PACKET_CONSUME_KEY = "redpacket:consume";
    public static final String RED_PACKET_KEY = "redpacket:";
    public static final String ID_KEY = "id:generator:redpacket";

    /**
     * 抢红包
     */
    @GetMapping("/rob")
    public int rob(int packetId,long userId){
        //验证用户是否已抢过红包
        Object obj = this.redisTemplate.opsForHash().get(RED_PACKET_CONSUME_KEY + packetId, String.valueOf(userId));
        if(obj == null){
            //随机从队列中弹出一个红包(解决了原子性操作问题：红包除了被抢走一个外，库存还需要减一)
            Object packet = this.redisTemplate.opsForList().leftPop(RED_PACKET_KEY + packetId);
            if(packet != null){
                //将抢到的红包进行保存
                this.redisTemplate.opsForHash().put(RED_PACKET_CONSUME_KEY +packetId,String.valueOf(userId),packet);
                log.info("用户={}抢到{}",userId,packet);
                //TODO 通过mq异步将数据落地到数据库中
                if(obj != null){
                    return (Integer) obj;
                }
            }
            //代表红包已经被抢完了
            return -1;
        }
        //代表该用户已经抢过红包了
        return -2;
    }

    /**
     *包红包
     */
    @GetMapping("/set")
    public long setRedPacket(int total,int count){
        Integer[] redPacket = this.splitRedPacket(total, count);
        //红包唯一标识
        Long id = this.incrementId();
        String key = RED_PACKET_KEY + id;
        //将拆解好的红包存入redis中，同时设置有效时间
        this.redisTemplate.opsForList().leftPushAll(key,redPacket);
        this.redisTemplate.expire(key,1, TimeUnit.DAYS);
        log.info("拆解的红包{}={}",key,redPacket);
        return id;
    }



    /**
     * 生成全局唯一id
     * @return
     */
    public Long incrementId(){
        Long packetId = this.redisTemplate.opsForValue().increment(ID_KEY, 1L);
        return packetId;
    }

    /**
     * 拆解红包
     * 1.红包金额需要被全部拆解完
     * 2.红包的金额不能相差太离谱
     */
    public Integer[] splitRedPacket(int total,int count){
        int use = 0;
        Integer[] array = new Integer[count];
        Random random  = new Random();
        for (int i = 0; i < count; i++) {
            if(i == count - 1){
                array[i] = total - use;
            }else {
                int avg = (total - use) * 2 / (count - i);
                array[i] = 1 +random.nextInt(avg - 1);
            }
            use = use + array[i];
        }
        return array;
    }

}
